// lua_interface.cpp

extern "C" {
    #include "luaext/lfs.h"
}

#include "l_request.hpp"
#include "l_reply.hpp"
#include "reply.hpp"
#include "lua_interface.hpp"
#include "l_utility.hpp"
#include "luredis.hpp"
#include <dirent.h>
#include "l_mobile_service.hpp"
#include "lua_interaction/luna.hpp"
#include "thrift_service/ipvn_service.hpp"



namespace http {
    namespace server3 {
        LuaInterface::LuaInterface(){
            lockLVM();
            L = luaL_newstate();
            luaL_openlibs(L);
            luaopen_lfs(L);
            // create table webqueue
            lua_newtable(L);
            lua_pushstring(L,__WEBQUEUE_REQUEST);
            lua_pushlightuserdata(L,NULL);
            lua_rawset(L,-3);
            lua_pushstring(L,__WEBQUEUE_REPLY);
            lua_pushlightuserdata(L,NULL);
            lua_rawset(L,-3);
            lua_setglobal(L,__WEBQUEUE_TABLE);

            // Allocate redis command buffer
            l_set_wq_buf(L,sdsallocate(__PREALLOCATE_SDS_LENGTH));

            // Binding C code
            l_register_request(L);
            l_register_reply(L);
            l_register_utility(L);
            register_luredis(L);
            l_register_mbl_service(L);

            Luna<ipvn_service>::Register(L);
            //Luna<dll_manager>::Register(L);

            cL = new_cL = NULL;
            std::cout << "Initializing LVM ..............\n";
            createNewCoroutine();
            unlockLVM();
        }

        /***********************************************************************
         Load business if necessary
        ***********************************************************************/
        void LuaInterface::do_business_interface(request& i_request, reply &o_reply){
            lockLVM();
            l_set_request(L,&i_request);
            l_set_reply(L,&o_reply);
            if(cL != NULL) {
                int status = lua_resume(cL,0); // resume current coroutine
                // The request was successfully processed
                if (status != LUA_YIELD) {
                    /*
                      CRITICAL: coroutine die
                      cL will soon be deleted.
                      Any reference to it will cause segmentation fault.
                    */
                    printf("[Thread %2x] [ERROR] when processing this request:%s\n",
                             (unsigned)pthread_self(), i_request.toStdString().data());
                    // catch any errors below
                    if (status == LUA_ERRRUN && lua_isstring(cL, -1)) {
                        printf("In Lua: %s \n",
                               lua_tostring(cL, -1));
                        lua_pop(cL, -1);
                    }
                    printf("Try to recover. Ignore the previous request.\n");
                    cL = NULL;
                    createNewCoroutine();
                }
            }
            unlockLVM();
        }

        LuaInterface::~LuaInterface(){
            sdsfree(l_get_wq_buf(L));
            lua_close(L);
        }

        void LuaInterface::createNewCoroutine(){
            //printf("Mutex: %2x Locked by %2x.\n",(unsigned)&mutex_update_LVM,(unsigned)pthread_self());
            new_cL = lua_newthread(L);
            // Remember: needed libraries must be loaded first
            chdir(__BIZ_CODE_DIR);
            int load_result = luaL_loadfile(new_cL,__MASTER_LUA);
            if(load_result == 0) {
                int status = lua_resume(new_cL,0);
                if (status == LUA_YIELD) {
                    cL = new_cL;
                    printf("[Thread %2x] A new LVM has been created.\n",
                            (unsigned)pthread_self());
                }
                else {
                    // catch any errors below
                    if (lua_isstring(new_cL, -1)) {
                        printf("[Thread %2x] [ERROR] Init Master failed: %s .\n",
                               (unsigned)pthread_self(), lua_tostring(new_cL, -1));
                        lua_pop(new_cL, -1);
                    }
                }
            }
            else {
                if(load_result == LUA_ERRSYNTAX)
                    printf("[ERROR] syntax error during pre-compilation.\n");
                else if (load_result == LUA_ERRMEM)
                    printf("[ERROR] Memory Allocation error.\n");
                else
                    printf("[ERROR] Cannot open file %s.\n",__MASTER_LUA);
            }
            // let's
            chdir("..");
            //printf("Mutex: %2x unlocked by %2x.\n",(unsigned)&mutex_update_LVM,(unsigned)pthread_self());
        }
    }
}

